#include <assert.h>
#include <ctype.h>
#include <locale.h>
#include <errno.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <pthread.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include<windows.h>


void variable_is_certain_qualified_type(void)
{
    printf("***** variable_is_certain_qualified_type *****\n");
    #define is_const_int(x) _Generic((&x), \
            const int *: "a const int", \
            int *: "a non-const int", \
            default: "of other type")
    /*
        i is a const int
        j is a non-const int
        k is of other type
    */

    /*
    However, if the type generic macro is implemented like this:
    i is a non-const int
    j is a non-const int
    k is of other type

    This is because all type qualifiers are dropped for the evaluation of the controlling expression of a _Generic
primary expression.
    */
    #define is_const_int(x) _Generic((x), \
            const int *: "a const int", \
            int *: "a non-const int", \
            default: "of other type")
}

/*
Generic selection based on multiple arguments

If a selection on multiple arguments for a type generic expression is wanted, 
and all types in question are arithmetic types, 
an easy way to avoid nested _Generic expressions is to use addition of the parameters in the controlling expression:

Here, the controlling expression (X)+(Y) is only inspected according to its type and not evaluated. The usual
conversions for arithmetic operands are performed to determine the selected type
*/
int max_int(int a, int b)
{
    a = (a>b)?  a: b;
    return a;
}
unsigned max_unsigned(unsigned a, unsigned b)
{
    a = (a>b)?  a: b;
    return a;
}
double max_double(double a, double b)
{
    a = (a>b)?  a: b;
    return a;
}
#define MAX(X, Y) _Generic((X)+(Y), \
        int: max_int, \
        unsigned: max_unsigned, \
        default: max_double) \
        ((X), (Y))


/*
For more complex situation, a selection can be made based on more than one argument to the operator, by nesting
them together.

This example selects between four externally implemented functions, that take combinations of two int and/or
string arguments, and return their sum.
*/
int AddIntInt(int a, int b)
{
    return a + b;
}
int AddIntStr(int a, const char* b)
{
    return a + atoi(b);
}
int AddStrInt(const char* a, int b )
{
    return atoi(a) + b;
}
int AddStrStr(const char* a, const char* b)
{
    return atoi(a) + atoi(b);
}
#define AddStr(y) \
        _Generic((y), int: AddStrInt, \
        char*: AddStrStr, \
        const char*: AddStrStr )
#define AddInt(y) \
        _Generic((y), int: AddIntInt, \
        char*: AddIntStr, \
        const char*: AddIntStr )
#define Add(x, y) \
        _Generic((x) , int: AddInt(y) , \
        char*: AddStr(y) , \
        const char*: AddStr(y)) \
        ((x), (y))


void type_generic_printing_macro(void)
{
    printf("***** type_generic_printing_macro *****\n");
    void print_int(int x) { printf("int: %d\n", x); }
    void print_dbl(double x) { printf("double: %g\n", x); }
    void print_default() { puts("unknown argument"); }
    
    #define print(X) _Generic((X), \
    int: print_int, \
    double: print_dbl, \
    default: print_default)(X)

    print(42);
    print(3.14);
    print("hello, world");
}

void main(void)
{
    const int i = 1;
    int j = 1;
    double k = 1.0;
    variable_is_certain_qualified_type();
    printf("i is %s\n", is_const_int(i));
    printf("j is %s\n", is_const_int(j));
    printf("k is %s\n", is_const_int(k));

    printf("MAX(1,2): %d\n", MAX(1,2));

    const int a = -123;
    char b[] = "4321";
    printf("Add( a , b ): %d\n", Add( a , b ));
    printf("Add( \"1\" , \"2\" ): %d\n", Add( "1" , "2" ));

    type_generic_printing_macro();
    system("pause");
}